#coding=utf-8
import stats

from sqlalchemy.exceptions import InvalidRequestError
from stseries.basic import average
from stconfig import Session as sess
from moneyflow import *

class TradeDay(object):
    '''交易日'''
    def __repr__(self):
        return self.date.isoformat()
        
    def index_of(self):
        
        s = self.fins
        tds = s.tds[:]
        tds.reverse()
        
        return tds.index(self) + 1
             
    def pre_n(self, n):
        '''前n个交易日'''
        tds = []
        
        t = self
        for i in range(n):
            pre = t.pre
            if not pre :return None
            
            tds.append(pre)
            t = pre
        
        return tds
        
    def pre_n_or_less(self, n):
        ''''''
        tds = []
        
        t = self
        for i in range(n):
            pre = t.pre
            if not pre: 
                if tds:return tds
                else:return None
            tds.append(pre)
            t = pre
        
        return tds
        
    def get_atr(self, fq=False):
        '''真实波动幅度'''
        name = 'atr'; sp = None; ip = None; bp =fq
        v = get_tcvalue(self, name, sp, ip, bp)
        if not v:
            #print 'can not get from cache base;'
            pre = self.pre
            if not pre:return None
                    
            p = self.price
            if not fq:
                v = max(p.highest-p.lowest,abs(p.highest-pre.price.close),
                        abs(pre.price.close-p.lowest) )
            else:
                a = p.fq('highest')-p.fq('lowest')
                b = abs(p.fq('highest')-pre.price.fq('close'))
                c = abs(pre.price.fq('close')-p.fq('lowest') )
                v = max(a, b, c)
                        
            set_tcvalue(self, name, sp, ip, bp, v)
        return v
    atr = property(fget=get_atr)
    
    def get_N(self, n=20, fq=False):
        '''真实波动幅度n天简单平均值'''
        name = 'N';sp = None; ip = n; bp = fq
        v = get_tcvalue(self, name, sp, ip, bp)
        if not v:
            atrs = []
            
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
            
            for td in tds:
                a = td.get_atr(fq=fq)
                if not a:return None
                atrs.append(a)
            v = average(atrs)
            
            set_tcvalue(self, name, sp, ip, bp, v)
        return v
    N = property(fget=get_N)
    
    def top(self, n, item='close', fq=False):
        '''前n天最高价(包括当天).'''
        name = 'top'; sp = item; bp = fq; ip = n
        v = get_tcvalue(self, name, sp, ip, bp)
        if not v:
        
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
            
            if not fq:
                cs = [getattr(t.price, item) for t in tds]
            else:
                cs = [t.price.fq(item) for t in tds]
                
            v = max(cs)
            set_tcvalue(self, name, sp, ip, bp, v)
        return v
        
    def lowest(self, n, item='close', fq=False):
        '''前n天最低价(包括当天).'''
        name = 'lowest'; sp = item; ip = n; bp=fq
        v = get_tcvalue(self, name, sp, ip, bp)
        
        if not v:
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
            
            if not fq:
                cs = [getattr(t.price, item) for t in tds]
            else:
                cs = [t.price.fq(item) for t in tds]
            v = min(cs)
            set_tcvalue(self, name, sp, ip, bp, v)
        return v 
        
    def avg_price(self, n, type_='sma', fq=False):
        '''该交易日前n天价格简单平均值'''
        name = 'ap'; sp = type_; ip = n; bp = fq
        v = get_tcvalue(self, name, sp, ip, bp)
        if not v:
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
        
            cs = [t.price.close for t in tds]
            if type_ == 'sma':
                v = average(cs)
            else:
                return
            set_tcvalue(self, name,sp, ip, bp, v)
            
        return v
        
    def avg_traderate(self, n, type_='sma', fq='Flase'):
        '''该交易日前n天换手率简单平均值'''
        name = 'a_tr'; sp = type_; ip = n; bp = fq
        
        v = get_tcvalue(self, name, sp, ip, bp)
        
        if not v:
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
        
            ts = [t.price.trade_rate for t in tds]
            #print ts
            if type_ == 'sma':
                v = average(ts)
            else:
                # ...
                return None
            set_tcvalue(self, name,sp, ip, bp, v)
            
        return v    
        
    def fluctuation_traderate(self, n, type_='std', fq='Flase'):
        '''该交易日前n天换手率波动:(标准差)'''
        name = 'f_tr'; sp = type_; ip = n; bp = fq
        
        v = get_tcvalue(self, name, sp, ip, bp)
        
        if not v:
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
        
            ts = [t.price.trade_rate for t in tds]
            #print ts
            if type_ == 'std':
                v = stats.stdev(ts)
            else:
                # ...
                return None
            set_tcvalue(self, name,sp, ip, bp, v)
        return v    
        
    def get_maxmoney(self, bors='b'):
        '''该交易日最大买(卖)单的金额'''
        name = 'max_money'; sp = bors; ip=None; bp=None
        v = get_tcvalue(self, name, sp, ip, bp)
        
        if not v:
            con = sess.connection() 
            sql = "select max(amount) from deals where tradeday_id = %s and bors = %s;"
            v = con.execute(sql, (self.id, bors)).fetchone()[0]
            if not v:v=0
            set_tcvalue(self, name, sp, ip, bp, v)
        return v
    max_bmoney = property(fget=get_maxmoney)
    
    def top_maxmoney(self, n=20, bors='b'):
        
        name = 'top_maxmoney'; sp = bors; ip=n; bp=None
        v = get_tcvalue(self, name, sp, ip, bp)
        
        if not v:
            tds = self.pre_n(n-1)
            if not tds:return None
            tds.insert(0, self)
            
            mbs = []
            for td in tds:
                mbs.append(td.get_maxmoney(bors))
            
            v = max(mbs)
            set_tcvalue(self, name, sp, ip, bp, v)
        return v

    def rtprice_on(self, t):
        '''在该交易日的成交明细数据中获得特定时刻的价格'''
        if len(self.deals) == 0 :return Nones
         
        con = sess.connection() 
        sql = '''
                 select price from deals where tradeday_id = %s 
                 and time < %s order by time desc limit 1 
              '''
        v = con.execute(sql, (self.id, t)).fetchone()
        if v:return v[0]
        else:
            return None
     
    def b_s(self, t=None):
        '''大买单总金额 － 大卖单'''
        import moneyflow.analyse as ma
        if not t:t = ma.get_dadan_threshold(self.price.close)
        #print t
        
        name = 'b_s'; sp = None; ip=t;bp=None
        v = get_tcvalue(self, name, sp, ip, bp )
        if not v:
            a = ma.Analyst1(self)
            r = a.stats(t)
            v = r['b-s'][1]
            set_tcvalue(self, name, sp, ip, bp, v )
        return v
    
class TdCache(object):
    
    def __init__(self, td, n, sp, ip, bp, v):
        self.td = td
        self.techname = n
        self.str_param = sp
        self.int_param = ip
        self.boolean_param = bp
        self.value = v
   

def get_tcvalue(td, n, sp, ip, bp):
    try:
        c = sess.query(TdCache).filter_by(td=td, techname=n, str_param=sp, int_param=ip, boolean_param=bp).one()
        return c.value
    except InvalidRequestError:
        return None

def set_tcvalue(td, n, sp, ip, bp, v): 
    sess.save(TdCache(td, n, sp, ip, bp, v))
    sess.commit()

class TDStats(object):
    def get_percent_of_up(self):
        return self.num_of_up * 100 / float(self.num_of_trading) 
    percent_of_up = property(fget=get_percent_of_up)

    def __repr__(self):
        return self.td.date.isoformat()
